//-------------------------------------- 
// easy-riscv ifu
//--------------------------------------

module EASY_RISCV_IFU #( 
    parameter   DAT_W   = 32   
    ,          ADDR_W   = 10            // 1024 x 32-bit = 4KB  
    ,           ENA_W   = DAT_W/8           
)
//--------------------------------------
(
//--------------------------------------
    input  wire        i_clk
,   input  wire        i_rst_n
,   input  wire        i_start_up
,   input  wire [31:0] i_start_pc
,   input  wire        i_jump_instr_vld_e0
,   input  wire [31:0] i_jump_instr_pc_e0
,   input  wire        i_fetch_stall_d0
//--------------------------------------
,   output reg         o_instr_vld_f1
,   output wire [31:0] o_dec_instr_f1
,   output reg  [31:0] o_cur_pc_f1
,   output reg         o_excp_pc_vld_f1
,   output reg  [1:0]  o_core_status
//--------------------------------------
);
//--------------------------------------
reg           [2:0]     start_up_ff         ;
wire                    start_pulse         ;
reg                     fetch_running       ;
wire                    fetch_enable_f0     ;
reg     [DAT_W-1:0]     cur_pc_f0           ;
reg     [DAT_W-1:0]     next_pc_f0          ;
wire                    instr_mem_cs_f0     ;
wire   [ADDR_W-1:0]     instr_mem_addr_f0   ;  
wire    [DAT_W-1:0]     instr_mem_rdata_f1  ;

//--------------------------------------
always @(posedge i_clk or negedge i_rst_n) begin
    if (i_rst_n == 1'b0) begin
        start_up_ff         <= 3'b0 ;
        o_excp_pc_vld_f1    <= 1'b0 ;
        o_core_status       <= 2'b0 ;
    end
    else begin
        start_up_ff         <= {start_up_ff[1:0], i_start_up}   ;
        o_excp_pc_vld_f1    <= fetch_enable_f0 & (|cur_pc_f0[1:0])  ;
        o_core_status       <= 2'b1 ;
    end
end

assign start_pulse  = (~start_up_ff[2]) & start_up_ff[1];

always @(posedge i_clk or negedge i_rst_n) begin
    if (!i_rst_n)
	    fetch_running   <= 1'b0 ;
    else if (start_pulse == 1'b1)
        fetch_running   <= 1'b1 ;
end

//--------------------------------------
assign fetch_enable_f0  = (start_pulse | fetch_running) & (~i_fetch_stall_d0)   ;
assign instr_mem_cs_f0  = fetch_enable_f0       ;
assign instr_mem_addr_f0= cur_pc_f0[2 +:ADDR_W] ;

EASY_RISCV_SPRAM_BE #(
    .DAT_W  (DAT_W  )
,   .ADDR_W (ADDR_W )
) U_INSTR_MEM (
    .clk  (i_clk                )  
,   .ce   (instr_mem_cs_f0      )
,   .we   ({ENA_W{1'b0}}        )
,   .addr (instr_mem_addr_f0    )
,   .din  ({DAT_W{1'b0}}        )
,   .dout (instr_mem_rdata_f1   )
);

//--------------------------------------
always @(*) begin
    if (start_pulse == 1'b1) begin
        cur_pc_f0 = i_start_pc  ;
    end
    else if (i_jump_instr_vld_e0 == 1'b1) begin
        cur_pc_f0 = i_jump_instr_pc_e0  ;
    end
    else begin
        cur_pc_f0 = o_cur_pc_f1 + 32'h4 ; 
    end
end

always @(posedge i_clk or negedge i_rst_n) begin
    if (i_rst_n == 1'b0) begin
        o_instr_vld_f1  <= 1'b0 ;
        o_cur_pc_f1     <= {DAT_W{1'b0}};
    end
    else if (fetch_enable_f0 == 1'b1) begin
        o_instr_vld_f1  <= 1'b1 ;
        o_cur_pc_f1     <= cur_pc_f0    ;
    end
    else begin
        o_instr_vld_f1  <= 1'b0 ;
    end
end

assign o_dec_instr_f1   = instr_mem_rdata_f1    ;

//--------------------------------------
endmodule               
                        
